package com.gao.r_hash.f._1;

import org.junit.Test;

/**
 * @author gao
 * @time 2022/06/28 20:26:02
 */
public class App2 {

    @Test
    public void test() {
        /*
            Integer.numberOfLeadingZeros(n) 返回 n 二进制形式中
            最高位1的左边有多少个0，比如 n 取值为 16，而16的二进制是：
            00000000 00000000 00000000 00010000
            最高位的1在第5位，该1的左边有27个0，所以该方法就会返回27
         */
        int n = Integer.numberOfLeadingZeros(16);
        System.out.println(n);
    }

    /**
     * 以下的resizeStamp是在ConcurrentHashMap扩容时用到的一个方法
     * 该方法用于返回一个“扩容戳”。这里提前学习一下，便于后续阅读源码
     */
    private static final int RESIZE_STAMP_BITS = 16;
    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;

    private int resizeStamp(int n) {
        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
    }

    @Test
    public void test2() {
        /*
            Integer.numberOfLeadingZeros(16) 返回 27，二进制是：
            00000000 00000000 00000000 00011011

            1 << 15 的结果是：00000000 00000000 10000000 00000000

            所以 27 | 1 << 15 的结果是：
            00000000 00000000 00000000 00011011
            00000000 00000000 10000000 00000000
            ___________________________________
            00000000 00000000 10000000 00011011
         */
        int rs = resizeStamp(16);
        System.out.println(rs);  // 32795
        System.out.println(Integer.toBinaryString(rs)); // 10000000 00011011

        /*
            00000000 00000000 10000000 00011011 << 16 = 10000000 00011011 00000000 00000000
            10000000 00011011 00000000 00000000 + 2   = 10000000 00011011 00000000 00000010

            sizeCtl的值最终为 10000000 00011011 00000000 00000010，在ConcurrentHashMap中，sizeCtl取这个值
            就表示当前的map正在进行扩容。sizeCtl的值此时分为两部分，高16位表示扩容的标识，低16位表示当前有几个线程正在
            同时对该map进行扩容：低16位的取值是 00000000 00000010，也就是2，实际扩容的线程个数为 2 - 1 = 1
         */
        int sizeCtl = (rs << RESIZE_STAMP_SHIFT) + 2;
        System.out.println(sizeCtl);
        System.out.println(Integer.toBinaryString(sizeCtl));
    }
}
